<?php

namespace App\Service\Pay\SysType;

use App\Enums\Check\CheckEnum;
use App\Enums\OpenShop\InvestmentPromotion\ErrCode;
use App\Exceptions\Custom\CustomHttpResponseException;
use App\Models\Cruise\CruiseCheckAgainstModel;
use App\Models\Fee\FeeAnnualOrderModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopSignOrderModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopSignOrderPayHistoryModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopSpaceDesignCostMappingModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopSpaceDesignSoftOutfitMappingModel;
use App\Service\BaseService;
use Illuminate\Database\Eloquent\Model;

/**
 * 不同sysType各支付阶段的不同处理方法
 */
abstract class BasePaySysTypeService extends BaseService
{
    protected ?OpenShopSignOrderModel $signOrderModel;
    protected Model                   $orderModel;
    protected int                     $sysType;
    protected int                     $userId;

    private function __construct(int $sysType, ?OpenShopSignOrderModel $signOrderModel, Model $orderModel, int $userId)
    {
        $this->sysType        = $sysType;
        $this->signOrderModel = $signOrderModel;
        $this->orderModel     = $orderModel;
        $this->userId         = $userId;
    }

    public static function getIns(
        int $sysType,
        ?OpenShopSignOrderModel $signOrderModel,
        ?Model $orderModel,
        string $bizId = '',
        int $userId = 0
    ): self {
        switch ($sysType) {
            case CheckEnum::SYS_TYPE_OPEN_SHOP_LEAGUE:
                $class      = PayLeagueService::class;
                $orderModel = $orderModel ?: $signOrderModel;
                break;
            case CheckEnum::SYS_TYPE_OPEN_SHOP_DESIGN:
                $class      = PayDesignService::class;
                $orderModel = $orderModel ?: OpenShopSpaceDesignCostMappingModel::query()
                                                                                ->where('preparationNo', $bizId)
                                                                                ->first();
                break;
            case CheckEnum::SYS_TYPE_OPEN_SHOP_DECORATE:
                $class      = PayDecorateService::class;
                $orderModel = $orderModel ?: OpenShopSpaceDesignSoftOutfitMappingModel::query()
                                                                                      ->where('preparationNo', $bizId)
                                                                                      ->first();
                break;
            case CheckEnum::SYS_TYPE_ANNUAL_FEE:
                $class = PayAnnualService::class;
                $orderModel = $orderModel ?: FeeAnnualOrderModel::query()->where('feeOrderNo', $bizId)->first();
                break;
            case CheckEnum::SYS_TYPE_AGAINST:
                $class = PayAgainstService::class;
                $orderModel = $orderModel ?: CruiseCheckAgainstModel::query()->where('serialNum', $bizId)->first();
                break;
            default:
                throw new CustomHttpResponseException(ErrCode::errCodeTrans(ErrCode::CODE_ERR_SYS_TYPE));
        }

        if (!$orderModel) {
            throw new CustomHttpResponseException(ErrCode::errCodeTrans(ErrCode::CODE_ERR_BIZ_ID));
        }

        return (new $class($sysType, $signOrderModel, $orderModel, $userId));
    }

    public function getOrderModel(): Model
    {
        return $this->orderModel;
    }

    /**
     * 支付入参校验
     * @return void
     */
    abstract public function valid(): void;

    /**
     * 支付金额明细
     * @return array
     */
    abstract public function priceLists(): array;

    /**
     * 支付幂等校验，true幂等
     * @return bool
     */
    abstract public function paySuccessCheck(): bool;

    /**
     * 支付成功更新主订单
     * @return void
     */
    abstract public function paySuccessSaveOrder(int $amount): void;

    /**
     * 支付成功之后的操作
     * @return void
     */
    abstract public function paySuccessAfter(): void;
}
